﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Collections;
using Vux.SVCore.Delegate;

namespace Vux.SVCore.Client.Network
{
    public class ClientListener
    {
        private TcpListener tcpListener;
        private Thread threadMain;
        private Hashtable htConnections = new Hashtable(10);
        private bool serverRuning;
        private int listenPort;

        public event MsgNotifyHandler MsgNotify;
        public event FailRegisterPortHandler FailRegisterPort;
        public event SocketErrorHandler SocketError;

        protected virtual void OnSocketError(object sender, Exception ex)
        {
            if (SocketError != null)
            {
                SocketError(sender, ex);
            }
        }

        protected virtual void OnFailRegisterPort(object sender, int port)
        {
            if (FailRegisterPort != null)
            {
                FailRegisterPort(sender, port);
            }
        }

        protected virtual void OnMsgNotify(object sender, string msg)
        {
            if (MsgNotify != null)
            {
                MsgNotify(sender, msg);
            }
        }       

        private byte[] m_img_data;

        public byte[] PictureData
        {
            get { return m_img_data; }
            set { m_img_data = value; }
        }

        public bool IsAlive
        {
            get { return serverRuning; }
        }

        public int Port
        {
            get { return listenPort; }
            set { listenPort = value; }
        }

        public ClientListener()
        {
            listenPort = 8989;
        }

        public ClientListener(int listenPort)
        {
            this.listenPort = listenPort;
        }

        public void startServer()
        {
            threadMain = new Thread(new ThreadStart(keepListening));
            threadMain.Name = "ClientListener";
            threadMain.Start();
        }

        ~ClientListener()
        {
            try
            {
                tcpListener.Stop();
                if (threadMain.IsAlive)
                {
                    threadMain.Abort();
                }
            }
            catch (Exception)
            {
                Console.WriteLine("Cannot disconnect Server\r\nProgram has terminated");
            }
        }

        public void stopListening()
        {
            tcpListener.Stop();
            serverRuning = false;
        }

        private void keepListening()
        {
            try
            {
                // Nghe (cho) d.chi phien ban 4, voi phai ban 6 thi khong nhan duoc
                IPAddress localAddr = IPAddress.Any;
                // Create listener
                tcpListener = new TcpListener(localAddr, listenPort);
                //tcpListener.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.AcceptConnection,
                // Start the TCP listener and listen for connections
                tcpListener.Start();
                OnMsgNotify(this, "SVCore đang chờ kết nối, cổng chờ: " + listenPort);
                serverRuning = true;
                while (serverRuning == true)
                {
                    try
                    {
                        var socketClient = tcpListener.AcceptSocket();
                        if (serverRuning == false)
                            break;
                        OnMsgNotify(this, "Da co 1 ket noi den!");
                        // var v_ip_endpoint = (IPEndPoint)tcpClient.Client.RemoteEndPoint;
                        // ApKeepServerConnection newConnection = new ApKeepServerConnection(v_ip_endpoint);
                        var v_connection_key = IPAddress.Parse(((IPEndPoint)socketClient.RemoteEndPoint).Address.ToString());
                        var v_svCoreClient = new SVCoreClient();
                        v_svCoreClient.AuthComplete += new AuthCompleteHandler(v_svCore_AuthComplete);
                        v_svCoreClient.SVCoreDisconnected += new SVCoreDisconnectedHandler(v_svCore_SVCoreDisconnected);
                        v_svCoreClient.MsgNotify += new MsgNotifyHandler(v_svCoreClient_MsgNotify);
                        v_svCoreClient.ImageData = m_img_data;
                        v_svCoreClient.Connect(socketClient);
                        htConnections[v_connection_key] = v_svCoreClient;
                        OnMsgNotify(this, "List count: " + htConnections.Count);
                        OnMsgNotify(this, "--------------------");
                        // Lưu vào danh sách kết nối được mở
                    }
                    catch (Exception)
                    {
                        tcpListener.Stop();
                        tcpListener.Start();
                    }
                }
            }
            catch (SocketException)
            {
                OnFailRegisterPort(this, listenPort);
            }
            catch (Exception ex)
            {
                OnSocketError(this, ex);
            }
        }

        private void v_svCoreClient_MsgNotify(object sender, string msg)
        {
            OnMsgNotify(sender, msg);
        }

        private void v_svCore_SVCoreDisconnected(object sender)
        {
            v_svCore_AuthComplete(sender, false);
        }

        private void v_svCore_AuthComplete(object sender, bool state)
        {
            var v_reject_server = (SVCoreClient)sender;
            v_reject_server.Disconnect();
            htConnections.Remove(v_reject_server);
            OnMsgNotify(this, "Đã ngắt kết nối tới server");
        }


        public void RejectAllConnection()
        {
            foreach (SVCoreClient item in htConnections.Keys)
            {
                item.Disconnect();
            }
        }

        #region Override
        public override string ToString()
        {
            //return IPAddress.Parse(((IPEndPoint)tcpListener.LocalEndpoint).Address.ToString()) + ":" + ((IPEndPoint)tcpListener.LocalEndpoint).Port.ToString();
            return base.ToString();
        }
        #endregion
    }
}
